

use std::{fs::remove_dir_all, io::{BufRead, BufReader}, process::{Command, Stdio}};

use chrono::NaiveDateTime;

use crate::error::WResult;

#[cfg(feature = "encrypt")]
use crate::encrypt::{decrypt_str_to_str, encrypt_str_to_str, decrypt, encrypt, WTASK_KEY};


#[cfg(feature = "encrypt")]
#[test]
fn test_encrypt1() -> WResult<()> {
    let t= format!("{WTASK_KEY}1").as_bytes().to_vec();
    let en = encrypt(&t, WTASK_KEY)?;
    let _ = decrypt(&en, WTASK_KEY)?;
    Ok(())
}


#[cfg(feature = "encrypt")]
#[test]
fn test_encrypt2() -> WResult<()> {
    let t= "hello， 你好";
    let tt = t.as_bytes().to_vec();
    let en = encrypt(&tt, "65FHHFI25U44QJS5TZ3ILK3TQSKQWF5BEXOOF12FIVZW63AKINCM")?;
    let de = decrypt(&en, "65FHHFI25U44QJS5TZ3ILK3TQSKQWF5BEXOOF12FIVZW63AKINCM")?;
    let t2 = String::from_utf8_lossy(&de).to_string();
    
    assert_eq!(t, t2);
    println!("en: {en:?}");

    Ok(())
}

#[cfg(feature = "encrypt")]
#[test]
fn test_decrypt3() -> WResult<()> {
    let raw = "65FHHFI25U44QJS5TZ3ILK3TQSKQWF5BEXOOF12FIVZW63AKINCM";
    let en_r = "02360340122401891656014418000649015624961932306001320090070806230328159306301221141607411260109507161215091800070000040522801221163232762436075000920905054005180456084614202167020427692044279000040965057603920528056715900198264013910266150001960835080415121560219624302651";
    let en = encrypt_str_to_str(raw, WTASK_KEY)?;
    assert_eq!(en_r, en);

    let de = decrypt_str_to_str(&en, WTASK_KEY)?;
    assert_eq!(raw, de);
    Ok(())
}





#[test]
fn test_datetime() {
    let fmt = "%Y-%m-%d %H:%M:%S";
    let date = "2024-02-19 22:42:50";
    let _ = NaiveDateTime::parse_from_str(date, fmt).unwrap();
}


#[test]
fn test_remove() {
    let p = "/root/tasks/wTask/wtask_data/task_archv";
    remove_dir_all(p).unwrap();
}

// pub struct AppAllServerStateShell {
//     child: Child,
//     stdout: AsyncBufReader<ChildStdout>,
//     stdin: ChildStdin,

// }

// impl AppAllServerStateShell {
//     async fn new() -> WResult<Self> {
//         println!("start shell");
//         let shell = std::env::var("SHELL").unwrap_or("bash".to_string());
//         let mut child = Command::new(shell)
//             .stdin(Stdio::piped())
//             .stdout(Stdio::piped())
//             .stderr(Stdio::piped())
//             .spawn()
//             .expect("Failed to start shell");

//         let mut stdin = child.stdin.take().expect("Failed to open stdin");
//         let stdout_raw = child.stdout.take().expect("Failed to open stdout");
//         let stdout = AsyncBufReader::new(stdout_raw);

//         // 配置
//         stdin.write_all("source ~/.bashrc".as_bytes()).await?;
        
//         Ok(Self { child, stdout, stdin })
//     }
// }

// impl AppAllServerStateShell {
//     pub async fn drop(&mut self) {
//         let _ = self.child.kill().await;
//         let _ = self.child.wait().await;
//     }
// }

// async fn shell_server(tx: Sender<Vec<u8>>, mut rx: Receiver<Vec<u8>>) -> WResult<()> {
//     let mut shell = AppAllServerStateShell::new().await?;
//     let mut buffer = [0; 128];
//     loop {
//         // println!("wait shell server inp or opt");
//         select! {
//             // 等待命令行输出
//             // n = shell.stdout.read(&mut buffer) => {
//             //     if n.is_err() {
//             //         break;
//             //     }
//             //     let n = n.unwrap();
//             //     if n == 0 {
//             //         break;
//             //     }
//             //     // println!("get cmd data opt");
//             //     let t = tx.send(buffer[..n].to_vec()).await;
//             //     if t.is_err() {
//             //         break;
//             //     }
//             // },
//             // 输入命令
//             data = rx.recv() => {
//                 if data.is_none() {
//                     break;
//                 }
//                 let data = data.unwrap();
//                 // println!("get cmd data ipt");
//                 let t = shell.stdin.write_all(&data).await;
//                 if t.is_err() {
//                     break;
//                 }
//             }
//         }
//     }
//     shell.drop().await;
//     Ok(())
// }


// pub async fn shell_cli(tx: Sender<Vec<u8>>, mut rx: Receiver<Vec<u8>>) -> WResult<()> {

//     spawn(async move {
//         loop {
//             // 命令行输出
//             let data = rx.recv().await;
//             if data.is_none() {
//                 break;
//             }
//             let data = data.unwrap();
//             let res = String::from_utf8_lossy(&data).to_string();
//             // println!("get opt");
//             print!("{}", res);
//             stdout().flush().unwrap();
//         }
//     });

//     loop {
//         // println!("wait shell cli inp or opt");
//         let mut buffer = String::new();
//         // println!("wait stdin");
//         std::io::stdin().read_line(&mut buffer).unwrap();
//         // println!("send stdin");
//         let t = tx.send(buffer.as_bytes().to_vec()).await;
//         // println!("send stdin over");
//         if buffer.starts_with("exit") || t.is_err() {
//             break;
//         }
//     }
//     Ok(())
// }


// // #[test]
// fn test_cmd_interactive() -> WResult<()> {
//     let (tx0, rx0) = channel::<Vec<u8>>(1024);
//     let (tx1, rx1) = channel::<Vec<u8>>(1024);
    
//     let runtime = runtime_init(4)?;
//     runtime.spawn(async move {
//         shell_server(tx0, rx1).await.unwrap();
//     });
//     runtime.block_on(async move {
//         shell_cli(tx1, rx0).await.unwrap();
//     });

//     Ok(())
// }



#[test]
fn test_cmd_podman() -> WResult<()> {
    let cmd = vec!["sh", "-c", "echo $env1"];
    
    let cmd = vec!["run", "-it", "--rm", "-e", "env1=value1", "rockylinux9"].into_iter().chain(cmd).map(| v | v.to_owned()).collect::<Vec<String>>();

    let mut child = Command::new("podman");
    if !cmd.is_empty() {
        child.args(&cmd);
    }

    // log
    let mut child = child
        .stdout(Stdio::piped())
        .stderr(Stdio::piped())
        .spawn()?;
    
    if let Some(stdout) = child.stdout.take() {
        let reader = BufReader::new(stdout);
        for line in reader.lines() {
            let line = line?;
            println!("{line}");
        }
    }
    let status = child.wait()?;

    // result
    assert!(status.success(), "cmd error");
    Ok(())
}

